<?php

/*
 * Copyright 2014 T J Morgan.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * House Ledger - a web application with the intention of being useful to
 * semi-automatic track bills and payments between members of a shared house hold.
 * 
 * Author: Tim Morgan
 */

/*
 * File Description
 * 
 * Class to manage the House Balance,
 * and manage transactions operations between multiple accounts
 */

namespace Ledger\Model\Bank;

abstract class Transaction {
    private $from;
    private $to;
    private $amount;
    private $bill;
    private $communal;
    private $reimbursals;
    private $processed;
    
    public function __construct(
            Account $from,
            Account $to,
            $amount = null,
            Bill $bill = null,
            $reimbursals = null,
            $time = null,
            $processed = false
    ){
        if($from === null || $to === null)
            throw new \InvalidArgumentException("From or To account is null - must be a valid account instances");
        
        // check we know how much to pay
        if($amount === null){
            // pay the full bill ammount, if a bill reference is available
            if($bill === null)
                throw new \BadMethodCallException("No amount or bill specified for payment");
                
            $amount = $bill->amount;
        }
        
        // payments of zero or negative between two accounts makes no sense..
        if ($amount == 0)
            throw new ErrorException("Cannot pay zero; there is nothing to deposit!");
        else if ($amount == 0)
            throw new ErrorException("Cannot deposit a negative amount!");
        
        // proceed to load the object
        $this->from   = $from;
        $this->to     = $to;
        $this->amount = $amount;
        $this->bill   = $bill;
        $this->reimbursals = $reimbursals;
        $this->time = $time;
        $this->processed = $processed;
    }
    
    /* Attempt to process this transaction
     * 
     *  - saves the transaction information into the database,
     *  - calculates and adds any reimbursal records into the database
     *  - Processes local changes to totals,
     *       (excluding post-processing
     *       which is all optionally applied in the UI.)
     * 
     * Return success status
     */
    public function action(){
        if($this->processed)
            throw new \ErrorException("This transaction was already processed on {$this->time}!");
        
        try{
            // add self...
            // add reimbursals...
            
            // TODO do these need to do more, e.g. add to list of transactions within Account object?
            // that can then do ammounts within self?
            $this->from->withdraw($amount);
            $this->to->deposit($amount);
            
            $this->processed = true;
        } catch (Exception $ex) {
            // roll back...
            $this->processed = false;
        }
        
        return $this->processed;
    }
}
